import React, {FC, useCallback, useEffect, useMemo, useRef, useState} from "react";
import {getObjByRule, isArray, isString} from "../../utils";
import {Select, Space} from "antd";
import useStateRef from "../../customUse/useStateRef.tsx";
import "./css/SelectForm.less";
import {AxiosGet} from "../../services/HttpService.tsx";
import Config from "../../Config.tsx";
import GlobalIcon from "../../global/GlobalIcon.tsx";

import useDebounce from "@core/customUse/useDebounce";

interface SelectFormProps {
    menuId: string,
    value?: any,
    ds?: any,
    url: string,
    params: any,
    format?: any,
    id: string,
    mode?: "multiple" | "tags" | undefined,
    showSearch?: boolean,
    allowClear?: boolean,
    disabled: boolean,
    options?: any[],
    onChange: Function,
    labelKey?: string,
    valueKey?: string,
    joinKey?: string,
    isAddSearchValue?: boolean,
    optionRender: any,
    open: any,
    getPopupContainer: any,
}

const SelectForm: FC<SelectFormProps> = (props) => {

    const selectOptionRef = useRef();
    const allSelectOptionRef = useRef<any[]>();

    const [selectOption, setSelectOption] = useStateRef([], selectOptionRef),
        [value, setValue] = useState<any>(undefined);

    const loadOption = useCallback(async () => {
        let {format = {id: "id", value: "value", label: "zhCn|usEn|ptBr"}, params = {}}: {
            format?: any,
            params: any
        } = props;
        let options: any[] = [];
        if (props.url) {
            const {data = []}: { data: any[] } = await AxiosGet(props.url, {
                ...params,
                [Config.axiosSerMenuKey]: props.menuId
            });
            options = data;
        } else if (props.options) {
            options = props.options || [];
        }
        options = options.map(node => {
            let item: any = isString(node) ? {id: node, value: node, label: node} : getObjByRule(node, {
                id: "id",
                value: "value",
                label: "zhCn|usEn|ptBr",
                ...format
            }, true)
            return {
                ...item
            }
        })
        setSelectOption(options);
        allSelectOptionRef.current = options;
    }, [props.options, props.url, props.params, props.menuId]);

    useEffect(() => {
        loadOption();
    }, [props.params, props.url, props.options]);

    useEffect(() => {
        if (value !== props.value) {
            if (!props.joinKey) {
                setValue(props.value)
            } else {
                if (value && value.join(props.joinKey) !== props.value) {
                    setValue(props.value.split(props.joinKey))
                }
            }
        }
    }, [props.value]);

    useEffect(() => {
        const {ds = {}}: { ds?: any } = props;
        let newValue = ds.value || props.value;
        if (newValue) {
            if (["multiple", "tags"].indexOf(props.mode) === -1 && isString(newValue)) {
                const {joinKey = ","}: { joinKey?: string } = props;
                setValue(isString(newValue) ? newValue.split(joinKey) : newValue);
            } else {
                setValue(newValue);
            }
        }
    }, [props.ds, props.mode]);

    const handelChange: Function = useCallback((value: any = "") => {
        const {joinKey}: { joinKey?: string } = props;
        setValue(value);
        props.onChange && props.onChange(isArray(value) && joinKey ? value.join(joinKey) : value);
    }, [props.onChange, props.joinKey]);

    const handelClear: Function = useCallback(() => {
        setSelectOption(JSON.parse(JSON.stringify(allSelectOptionRef.current)));
    }, []);

    const handelSearch: Function = useDebounce((text: string) => {
        if (props.mode == 'tags') {
            return
        }
        const {labelKey = "label", valueKey = "value", isAddSearchValue = false}: {
            labelKey?: string,
            valueKey?: string,
            isAddSearchValue?: boolean
        } = props;
        let newSelectOption: any[] = allSelectOptionRef.current.filter((item: any) => {
            return item[labelKey].indexOf(text) !== -1 || item[valueKey].indexOf(text) !== -1
        });
        if (isAddSearchValue && !newSelectOption.length) {
            let node: object = {
                [labelKey]: text,
                [valueKey]: text
            }
            newSelectOption.push(node);
        }
        setSelectOption(JSON.parse(JSON.stringify(newSelectOption)));
    }, 500, [selectOption, props.labelKey, props.valueKey, props.isAddSearchValue])

    const renderSelectForm = useMemo(() => {
        if (!selectOptionRef.current) {
            return null
        }
        const {
            labelKey = "label",
            valueKey = "value",
            mode,
            showSearch = true,
            allowClear = true,
            optionRender,
            open,
            getPopupContainer,
            isAddSearchValue,
            iconId
        } = props;
        const SelectProps: any = {
            mode,
            value,
            showSearch,
            allowClear,
            disabled: props.disabled,
            options: selectOptionRef.current,
            fieldNames: {label: labelKey, value: valueKey},
            filterOption: (input: any, option: any) =>
                (option?.label ?? '').includes(input),
            // onSearch: handelSearch,
            onChange: handelChange,
            onClear: handelClear
        }
        if (isAddSearchValue) {
            SelectProps.onSearch = handelSearch
        }
        return (
            <div className="sf_core_select_form">
                <Select
                    optionRender={optionRender ? optionRender : (optionItem: any) => {
                        return (
                            <Space>
                                {
                                    optionItem[labelKey] == optionItem[valueKey] && isAddSearchValue ?
                                        <GlobalIcon name="icon-xinbiaoqian"/>
                                        : null
                                }
                                {iconId && optionItem.data[iconId] ?
                                    <GlobalIcon name={optionItem.data[iconId]}/> : null}
                                <span role="img" aria-label={optionItem[labelKey]}>
                                    {optionItem[labelKey]}
                                </span>
                            </Space>
                        )
                    }}
                    getPopupContainer={getPopupContainer ? getPopupContainer : ''}
                    open={open}
                    {...SelectProps}
                />
            </div>
        )
    }, [props, selectOption, value])

    return (renderSelectForm)
};

export default React.memo(SelectForm);
